package cn.kimoon.dau_android;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import cn.kimoon.dau_android.Utility.SPUtils;

/**
 * Created by xiangdong on 2016/11/23.
 */

public class PatrolActivity extends AppCompatActivity implements View.OnClickListener {

    private BluetoothAdapter adapter;
    private BluetoothAdapter.LeScanCallback mLeScanCallback;    // BLE扫描返回
    private BluetoothGatt mBluetoothGatt;   // 蓝牙交换数据的句柄
    private TextView logTextView;
    private Button startPatrolBtn;

    final private String serviceUUID = "FFE0";            // 这里的接口无法搜索16bit的UUID
    final private String characteristicUUID = "FFE1";     // Characteristics的UUID
    final private String peripheralName = "SU3110";       // 蓝牙外设的名字

    public static final int SIGN_STATE_NOT = 0;           // 没有签到
    public static final int SIGN_STATE_ON = 1;            // 正在签到
    public static final int SIGN_STATE_HAVE = 2;          // 成功签到

    private int patrolState;                              // 用于表明当前处于什么状态

    public void setPatrolState(final int patrolState) {
        this.patrolState = patrolState;

        // 设置界面，只能放在主线程
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                String[] textStr = new String[]{getString(R.string.patrol_register),
                        getString(R.string.patrol_scan_peripheral),
                        getString(R.string.patrol_register_success)};
                startPatrolBtn.setText(textStr[patrolState]);
            }
        });
    }

    final private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override  //当连接上设备或者失去连接时会回调该函数
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            System.out.println("尝试连接的状态旧" + status + "新状态" + newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) { //连接成功
                System.out.println("连接外设成功" + gatt.getDevice().getName());
                updateLog(getString(R.string.patrol_connect_success) + "(" + gatt.getDevice().getName() + ")");
                gatt.discoverServices(); //连接成功后就去找出该设备中的服务 private BluetoothGatt mBluetoothGatt;
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {  //连接失败
                System.out.println("连接外设失败");
                updateLog(getString(R.string.patrol_connect_fail) + "(" + gatt.getDevice().getName() + ")");
                setPatrolState(SIGN_STATE_NOT);
                System.out.println("连接外设失败，重新扫描");
                startScan();
            }
        }

        @Override  //当设备是否找到服务时，会回调该函数
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {   //找到服务了
                //在这里可以对服务进行解析，寻找到你需要的服务
                displayGattServices(getSupportedGattServices());
            } else {
                System.out.println("onServicesDiscovered received: " + status);
            }
        }

        @Override  //当读取设备时会回调该函数
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            System.out.println("onCharacteristicRead");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //读取到的数据存在characteristic当中，可以通过characteristic.getValue();函数取出。然后再进行解析操作。
                //int charaProp = characteristic.getProperties();if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0)表示可发出通知。  判断该Characteristic属性
            }
        }

        @Override //当向设备Descriptor中写数据时，会回调该函数
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            System.out.println("onDescriptorWriteonDescriptorWrite = " + status + ", descriptor =" + descriptor.getUuid().toString());
        }

        @Override //设备发出通知时会调用到该接口(前提是要先注册通知)
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            System.out.println("--------onCharacteristicChanged-----");
            if (characteristic.getValue() != null) {
                String result = characteristic.getStringValue(0);
                System.out.println("收到蓝牙外设的值:" + result);
                if (characteristic.getUuid().toString().toUpperCase().contains(characteristicUUID) && result.startsWith("[NAME]OK")) {
                    // 断开监听
                    mBluetoothGatt.setCharacteristicNotification(characteristic, false);
                    System.out.println("签到成功，断开连接");
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String t = format.format(new Date());
                    updateLog(t + " " + getString(R.string.patrol_register_success));
                    updateLog(getString(R.string.patrol_disconnect) + "(" + gatt.getDevice().getName() + ")");
                    setPatrolState(SIGN_STATE_HAVE);
                    stopScan();
                }
            }
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            System.out.println("rssi = " + rssi);
        }

        @Override //当向Characteristic写数据时会回调该函数
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            System.out.println("--------write success----- status:" + status);
            if (status != 0) {
                System.out.println("写数据到外设失败");
                updateLog(getString(R.string.patrol_write_data_fail));
                setPatrolState(SIGN_STATE_NOT);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_patrol);

        initSubViews();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        System.out.println("签到页面摧毁------------------*********--------------");
        // 断开蓝牙
        stopScan();
    }

    private void initSubViews() {
        Button backButton = (Button) findViewById(R.id.patrol_back_button);
        backButton.setOnClickListener(this);

        startPatrolBtn = (Button) findViewById(R.id.start_patrol_btn);
        startPatrolBtn.setOnClickListener(this);

        logTextView = (TextView) findViewById(R.id.patrol_log);
        logTextView.setMovementMethod(ScrollingMovementMethod.getInstance());

        mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(final BluetoothDevice device, int rssi, final byte[] scanRecord) {
//                ArrayUtils.reverse(scanRecord);// 数组反转
                // 将Byte数组的数据以十六进制表示并拼接成字符串
                StringBuffer str = new StringBuffer();
                int i = 0;
                for (byte b : scanRecord) {
                    i = (b & 0xff);
                    str.append(Integer.toHexString(i));
                }
                String discoveryServceID = str.toString();

                // 这里可能不在UI线程，处理界面的时候需要注意
                System.out.println("发现BLE蓝牙外设： " + device.getName() + " discoveryServerID -> " + discoveryServceID);
                updateLog(getString(R.string.patrol_discover_peripheral) + "(" + device.getName() + ")");
                // 名字一样、协议一样，就开始建立连接
                if (device.getName().startsWith(peripheralName)) {
                    fish(device);
                }
            }
        };
    }

    //按键处理
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.patrol_back_button:
                backToSuperActivity();
                break;
            case R.id.start_patrol_btn:
                startPatrolBtnTapped();
                break;
        }
    }

    // 返回上一级
    private void backToSuperActivity() {
        finish();
    }

    // 开启巡更功能
    private static final int REQUEST_FINE_LOCATION=0;
    private void startPatrolBtnTapped() {
        // 蓝牙模块要求只支持BLE4.0,所以这里要对手机进行判断
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(this, R.string.patrol_not_support_bluetooth, Toast.LENGTH_SHORT).show();
            return;
        }

        if (adapter == null) {
            adapter = BluetoothAdapter.getDefaultAdapter();
            if (adapter == null) {
                Toast.makeText(this, R.string.patrol_not_support_bluetooth, Toast.LENGTH_SHORT).show();
                return;
            }
        }

        if (patrolState == SIGN_STATE_HAVE) {
            Toast.makeText(this, R.string.patrol_have_register, Toast.LENGTH_SHORT).show();
            return;
        }

        if (patrolState == SIGN_STATE_ON) {
            Toast.makeText(this, R.string.patrol_scan_peripheral, Toast.LENGTH_SHORT).show();
            return;
        }

        // 如果设备没有被打开
        if (!adapter.isEnabled()) {
            // 启动新的activity，打开蓝牙
            updateLog(getString(R.string.patrol_bluetooth_close));
            System.out.println("跳转到打开蓝牙界面");
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivity(intent);
        }

        // android6.0以上需要打开定位才能扫描，略蛋疼
        if (Build.VERSION.SDK_INT >= 23) {
            //校验是否已具有模糊定位权限
            if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                //判断是否需要 向用户解释，为什么要申请该权限
                if(ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_COARSE_LOCATION))
                    Toast.makeText(this, R.string.patrol_need_location, Toast.LENGTH_SHORT).show();

                ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_FINE_LOCATION);
                return;
            }
        }

//        // 这里已经配对的，目前这里用不上
//        // 获取所有已经配对的蓝牙，得到一个蓝牙设备集
//        Set<BluetoothDevice> devices = adapter.getBondedDevices();
//        System.out.println("已配对的蓝牙数量" + devices.size());
//        if (devices.size() > 0) {
//            //如果有已经配对的蓝牙，那么用迭代逐个打印出来
//            for(Iterator iterator = devices.iterator(); iterator.hasNext();)
//            {
//                BluetoothDevice bluetoothDevice = (BluetoothDevice)iterator.next();
//                System.out.println(bluetoothDevice.getAddress());
//            }
//        }

        startScan();
    }

    public List<BluetoothGattService> getSupportedGattServices() {
        if (mBluetoothGatt == null)
            return null;
        return mBluetoothGatt.getServices();   //此处返回获取到的服务列表
    }

    private void displayGattServices(List<BluetoothGattService> gattServices) {
        if (gattServices == null)
            return;
        for (BluetoothGattService gattService : gattServices) { // 遍历出gattServices里面的所有服务
            List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
            if (gattService.getUuid().toString().toUpperCase().contains(serviceUUID)) {
                // 包涵FFE0的服务
                System.out.println("找到包含FFE0的Service :" + gattService.getUuid().toString());
                for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { // 遍历每条服务里的所有Characteristic
                    System.out.println("服务里面的characteristic的UUID = " + gattCharacteristic.getUuid().toString());
                    if (gattCharacteristic.getUuid().toString().toUpperCase().contains(characteristicUUID)) {
                        // 有哪些UUID，每个UUID有什么属性及作用，一般硬件工程师都会给相应的文档。我们程序也可以读取其属性判断其属性。
                        // 此处可以可根据UUID的类型对设备进行读操作，写操作，设置notification等操作
                        // BluetoothGattCharacteristic gattNoticCharacteristic 假设是可设置通知的Characteristic
                        // BluetoothGattCharacteristic gattWriteCharacteristic 假设是可读的Characteristic
                        // BluetoothGattCharacteristic gattReadCharacteristic  假设是可写的Characteristic

                        // 监听Characteristic
                        mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);

                        String name = (String) SPUtils.get(this, MainActivity.DAU_SP_USER_NAME, "");
                        String str = "[NAME]" + name + "\r\n";
                        gattCharacteristic.setValue(str);
                        wirteCharacteristic(gattCharacteristic);    // 写入响应
                        System.out.println("找到服务里面的characteristic的UUID = " + gattCharacteristic.getUuid().toString());
                        updateLog(getString(R.string.patrol_request_register));
                    }
                }
            }
        }
    }

    public void wirteCharacteristic(BluetoothGattCharacteristic characteristic) {
        if (adapter == null || mBluetoothGatt == null) {
            System.out.println("BluetoothAdapter not initialized");
            return;
        }

        mBluetoothGatt.writeCharacteristic(characteristic);
    }

    // 连接蓝牙外设
    private void fish(final BluetoothDevice device) {
        System.out.println("开始建立连接");
        updateLog(getString(R.string.patrol_start_connect) + "(" + device.getName() + ")");
        // 每次连接前，先close之前的连接，防止重复多次连接
        if (mBluetoothGatt != null) {
            mBluetoothGatt.close();
        }

        // 建立连接需要在主线程
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mBluetoothGatt = device.connectGatt(PatrolActivity.this, false, mGattCallback);
                System.out.println("建立连接得到的Gatt ==" + mBluetoothGatt);
//                adapter.stopLeScan(mLeScanCallback); //放在这里会出问题，可能是线程吧，所以不能在这里
            }
        });

        System.out.println("停止扫描");
        // 这里确实需要断开扫描，因为不停止扫描的话，可能会建立多个连接，导致无法完全断开
        adapter.stopLeScan(mLeScanCallback); //放在这里会出问题，可能是线程吧，所以不能在这里
    }

    // 开始扫描
    private void startScan() {
        if (adapter.isEnabled()) {
            boolean result = adapter.startLeScan(mLeScanCallback);
            updateLog(getString(R.string.patrol_bluetooth_open));
            if (result) {
                System.out.println("开始扫描BLE蓝牙设备");
                updateLog(getString(R.string.patrol_scan_peripheral));
                setPatrolState(SIGN_STATE_ON);
            } else {
                System.out.println("开始扫描BLE蓝牙设备失败");
                updateLog("startLeScan() failed");
            }
        }
    }

    // 停止扫描
    private void stopScan() {
        System.out.println("断开链接，停止扫描");
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mBluetoothGatt != null) {
                    System.out.println("----断开Gatt------");
                    mBluetoothGatt.disconnect();            // 断开链接
                }
//                mBluetoothGatt.close();                 // 关闭链接(放在这里，也会出问题。所以就放到外边去了，感觉是线程问题)
//                adapter.stopLeScan(mLeScanCallback);    // 停止扫描
            }
        });
//        mBluetoothGatt.disconnect();            // 断开链接(断开连接要放到主线程里面)
        if (mBluetoothGatt != null) {
            mBluetoothGatt.close();                 // 关闭链接
        }
        if (adapter != null) {
            System.out.println("----断开adapter------");
            adapter.stopLeScan(mLeScanCallback);    // 停止扫描
        }
    }

    private void updateLog(final String string) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                logTextView.setVisibility(View.VISIBLE);
                logTextView.setText(logTextView.getText() + "\n" + string);
            }
        });
    }
}
